Image('title.png')
import os
import geopandas as gpd
import osmnx as ox
import networkx as nx
from shapely.geometry import Point
import numpy as np
import pandas as pd
from tqdm import tqdm
import matplotlib.pyplot as plt
from pyproj import Transformer
from matplotlib.colors import TwoSlopeNorm
from IPython.display import clear_output
from IPython.display import Image
import pickle
import warnings
warnings.filterwarnings(action='ignore')
import sys
#sys.stdout = open(os.devnull, 'w')
sys.stderr = open(os.devnull, 'w')
root = os.getcwd()
pd.options.display.float_format = '{:.0f}'.format
plt.rcParams['font.family'] = 'Malgun Gothic'
subway 공간데이터
with open("subway_name.pickle","rb") as fi:
subway_name = pickle.load(fi)
subway_name = subway_name.rename(columns={'subway_name' : 'SUBWAY_STA'} )
data_path = os.path.join(root, 'subway_statn_info')
subway = gpd.read_file(os.path.join(data_path,'subway_statn_info.shp'),encoding='EUC-KR')
subway['SUBWAY_STA'] = subway_name['SUBWAY_STA']
subway.head()
| SUBWAY_STA | OPNG_YMD | SUBWAY__01 | geometry | |
|---|---|---|---|---|
| 0 | 온수역 | None | 57 | POINT (184330.338 443625.386) |
| 1 | 천왕역 | None | 58 | POINT (185637.754 443167.709) |
| 2 | 남구로역 | None | 59 | POINT (190001.728 442926.56) |
| 3 | 구로디지털단지역 | 20070807 | 60 | POINT (191231.554 442905.09) |
| 4 | 도림천역 | None | 142 | POINT (189654.644 446092.355) |
# 지하철역 좌표추출
subway = subway.to_crs(epsg=5179) # 좌표계 변환
sub_crds = [[list(subway.geometry[i].coords)[0][0], list(subway.geometry[i].coords)[0][1]] for i in range(len(subway))]
sub_crds_arr = np.array(sub_crds)
스타벅스 이디야 공간데이터
ediya = pd.read_csv('ediya.csv')
starbucks = pd.read_csv('starbucks.csv')
# 좌표계 변환
transformer = Transformer.from_crs("epsg:4326", "epsg:5179", always_xy=True)
ediya['longitude'],ediya['latitude'] = transformer.transform(ediya['lng'],ediya['lat'])
starbucks['longitude'],starbucks['latitude'] = transformer.transform(starbucks['lng'],starbucks['lat'])
ediya = ediya[['gu','title','address','lat','lng','longitude','latitude']]
geometry = [Point(xy) for xy in zip(ediya['longitude'], ediya['latitude'])]
ediya_geo = gpd.GeoDataFrame(ediya, geometry=geometry)
ediya_geo.head()
| gu | title | address | lat | lng | longitude | latitude | geometry | |
|---|---|---|---|---|---|---|---|---|
| 0 | 강남구 | 강남YMCA점 | 서울 강남구 논현동 | 38 | 127 | 958615 | 1946147 | POINT (958615.456 1946146.863) |
| 1 | 강남구 | 강남구청역아이티웨딩점 | 서울 강남구 학동로 338 (논현동, 강남파라곤) | 38 | 127 | 959362 | 1946462 | POINT (959361.721 1946461.887) |
| 2 | 강남구 | 강남논현학동점 | 서울 강남구 논현로131길 28 (논현동) | 38 | 127 | 958249 | 1946316 | POINT (958248.791 1946316.358) |
| 3 | 강남구 | 강남대치점 | 서울 강남구 역삼로 415 (대치동, 성진빌딩) | 38 | 127 | 960431 | 1944780 | POINT (960430.89 1944779.522) |
| 4 | 강남구 | 강남도산점 | 서울 강남구 도산대로37길 20 (신사동) | 38 | 127 | 958600 | 1947101 | POINT (958599.662 1947101.46) |
starbucks = starbucks[['구','title','address','lat','lng','longitude','latitude']]
starbucks = starbucks.rename(columns={'구' : 'gu'})
geometry = [Point(xy) for xy in zip(starbucks['longitude'], starbucks['latitude'])]
starbucks_geo = gpd.GeoDataFrame(starbucks, geometry=geometry)
starbucks_geo.head()
| gu | title | address | lat | lng | longitude | latitude | geometry | |
|---|---|---|---|---|---|---|---|---|
| 0 | 강남구 | 역삼아레나빌딩 | 서울특별시 강남구 언주로 425 (역삼동) | 38 | 127 | 959612 | 1944745 | POINT (959612.309 1944744.958) |
| 1 | 강남구 | 논현역사거리 | 서울특별시 강남구 강남대로 538 (논현동) | 38 | 127 | 957775 | 1945763 | POINT (957774.861 1945762.698) |
| 2 | 강남구 | 신사역성일빌딩 | 서울특별시 강남구 강남대로 584 (논현동) | 38 | 127 | 957634 | 1946180 | POINT (957634.047 1946179.786) |
| 3 | 강남구 | 국기원사거리 | 서울특별시 강남구 테헤란로 125 (역삼동) | 37 | 127 | 958588 | 1944576 | POINT (958588.421 1944575.806) |
| 4 | 강남구 | 대치재경빌딩 | 서울특별시 강남구 남부순환로 2947 (대치동) | 37 | 127 | 961334 | 1944025 | POINT (961333.832 1944024.617) |
도로네트워크 공간데이터
with open('G_utm.pkl', 'rb') as file:
G_utm = pickle.load(file)
'지하철역 & 스벅/이디야'과 '도로네트워크(G_utm)'와의 매핑
nearest_sub, dist_sub = ox.distance.nearest_nodes(G_utm, X=sub_crds_arr[:,0], Y=sub_crds_arr[:,1], return_dist=True)
nearest_sb, dist_sb = ox.distance.nearest_nodes(G_utm, X=starbucks['longitude'], Y=starbucks['latitude'], return_dist=True)
nearest_id, dist_id = ox.distance.nearest_nodes(G_utm, X=ediya['longitude'], Y=ediya['latitude'], return_dist=True)
nearest( G_utm 노드)에 해당하는 G_utm의 index추출
G_utm_nodes = list(G_utm.nodes)
subway_idx = [G_utm_nodes.index(nearest_sub[i]) for i in range(len(nearest_sub))]
sb_idx = [G_utm_nodes.index(nearest_sb[i]) for i in range(len(nearest_sb))]
id_idx = [G_utm_nodes.index(nearest_id[i]) for i in range(len(nearest_id))]
gutm_locat_3p(G_utm,starbucks,ediya,sub_crds_arr,'스타벅스','이디야','지하철역','서울특별시 도로네트워크 지하철역,스타벅스,이디야 매장')
구별 경계 지도 데이터
si_file = "./sig_emd/sig_20230729/sig.shp"
sigu = gpd.read_file(si_file, encoding='euckr')
sigu = sigu.set_crs(epsg=5179) # sigu 수동으로 좌표계를 설정
서울만 추출 & 스타벅스&이디야 지하철 데이터 합치기
sigu['CTPRVN_CD'] = [str(num)[:2] for num in sigu['SIG_CD']]
sigu = sigu.loc[sigu['CTPRVN_CD']=='11']
starbucks_count = starbucks_geo.groupby('gu').size().reset_index(name='starbucks_count')
starbucks_count = starbucks_count.rename(columns={'gu' : 'SIG_KOR_NM'} )
ediya_count = ediya_geo.groupby('gu').size().reset_index(name='ediya_count')
ediya_count = ediya_count.rename(columns={'gu' : 'SIG_KOR_NM'} )
sigu = sigu.merge(starbucks_count, on='SIG_KOR_NM')
sigu = sigu.merge(ediya_count, on='SIG_KOR_NM')
스타벅스&이디야 매장 수 차이 변수 생성
sigu['sb_id'] = sigu['starbucks_count']-sigu['ediya_count']
for index, rows in sigu.iterrows():
if rows['sb_id']>0:
sigu.at[index, 'sb_id_1']= "SB: +"+str(rows['sb_id'])
elif rows['sb_id']==0:
sigu.at[index, 'sb_id_1']= "동일"
else:
sigu.at[index, 'sb_id_1']= "ED: +"+str(rows['sb_id']*-1)
공시지가 데이터
with open("rprice.pickle","rb") as fi:
rprice = pickle.load(fi)
rprice['공시지가'] = rprice['공시지가'].astype(float)
rprice = rprice[rprice['시도명']=="서울특별시"]
rprice_gu = rprice.groupby('시군구명')['공시지가'].mean().reset_index(name='공시지가 평균')
rprice_gu = rprice_gu.rename(columns={'시군구명' : 'SIG_KOR_NM'} )
sigu = sigu.merge(rprice_gu, on='SIG_KOR_NM')
구별 지하철역 수
gu_sub = pd.read_csv('서울교통공사_자치구별지하철역정보_20240628.csv',encoding='euckr')
gu_sub = gu_sub.rename(columns={'자치구' : 'SIG_KOR_NM'} )
sigu = sigu.merge(gu_sub.drop(columns = ['해당역(호선)']), on='SIG_KOR_NM')
sigu.head()
| SIG_CD | SIG_ENG_NM | SIG_KOR_NM | geometry | CTPRVN_CD | starbucks_count | ediya_count | sb_id | sb_id_1 | 공시지가 평균 | 역개수 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 11110 | Jongno-gu | 종로구 | POLYGON ((956615.453 1953567.199, 956621.579 1... | 11 | 39 | 35 | 4 | SB: +4 | 5938143 | 15 |
| 1 | 11140 | Jung-gu | 중구 | POLYGON ((957890.386 1952616.746, 957909.908 1... | 11 | 52 | 34 | 18 | SB: +18 | 9949269 | 23 |
| 2 | 11170 | Yongsan-gu | 용산구 | POLYGON ((953115.761 1950834.084, 953114.206 1... | 11 | 24 | 13 | 11 | SB: +11 | 6812485 | 10 |
| 3 | 11200 | Seongdong-gu | 성동구 | POLYGON ((959681.109 1952649.605, 959842.412 1... | 11 | 14 | 20 | -6 | ED: +6 | 4884766 | 14 |
| 4 | 11215 | Gwangjin-gu | 광진구 | POLYGON ((964825.058 1952633.25, 964875.565 19... | 11 | 19 | 20 | -1 | ED: +1 | 4371127 | 11 |
#round(sigu['공시지가 평균'].median()),round(sigu['공시지가 평균'].min()),round(sigu['공시지가 평균'].max())
#sigu[sigu['공시지가 평균']==sigu['공시지가 평균'].median()].SIG_KOR_NM,sigu[sigu['공시지가 평균']==sigu['공시지가 평균'].min()].SIG_KOR_NM,sigu[sigu['공시지가 평균']==sigu['공시지가 평균'].max()].SIG_KOR_NM
공시지가 중간값: 3,986,627원(관악구), 공시지가 최소: 2,390,374원(도봉구), 공시지가 최대: 11,925,742원(강남구)
add_text_sb = "평균 공시지가가 높을수록 붉은색, 낮을수록 파랑색"
title_text = "서울 구별 평균 공시지가"
map_color_text(sigu,'공시지가 평균','coolwarm','평균 공시지가 최소값 ~ 최대값 ( 단위:천만원 )','SIG_KOR_NM',add_text_sb,title_text)
#round(sigu['역개수'].median()),round(sigu['역개수'].min()),round(sigu['역개수'].max())
#sigu[sigu['역개수']==sigu['역개수'].median()].SIG_KOR_NM,sigu[sigu['역개수']==sigu['역개수'].min()].SIG_KOR_NM,sigu[sigu['역개수']==sigu['역개수'].max()].SIG_KOR_NM
지하철역 수 중간값: 11(광진구), 지하철역 수 최소: 1(금천구), 지하철역 수 최대: 23(송파구)
add_text_sb = '역개수가 더 많을수록 붉은색, 적을수록 파랑색'
title_text = '서울 구별 지하철역 수 COLORMAP'
map_color_text(sigu,'역개수','coolwarm','역개수 최소값 ~ 최대값','SIG_KOR_NM',add_text_sb,title_text)
#starbucks_geo.shape,ediya_geo.shape #
스타벅스 매장 수: 614, 이디야 매장수: 686 ( 이디야가 72개 더 많다.)
add_text_sb = '스타벅스(SB)가 더 많을수록 붉은색, 이디야(ED)가 더 많을수록 파랑색'
title_text = "서울 구별 '스타벅스'&'이디야' 매장 수 차이"
map_color_text(sigu,'sb_id','coolwarm','매장 수 차이 최소값 ~ 최대값','sb_id_1',add_text_sb,title_text)
Image('seoul_sb_ed01.png')
스타벅스 최근접 지하철역 & 거리
starbucks_1 = nearest_fun(G_utm,nearest_sb,nearest_sub,starbucks)
이디야 최근접 지하철역 & 거리
ediya_1 = nearest_fun(G_utm,nearest_id,nearest_sub,ediya)
sb_gu_mean = starbucks_1.groupby('gu')['dist2sub'].mean().reset_index()
sb_gu_mean = sb_gu_mean.sort_values(by='dist2sub', ascending=True)
id_gu_mean = ediya_1.groupby('gu')['dist2sub'].mean().reset_index()
id_gu_mean = id_gu_mean.sort_values(by='dist2sub', ascending=True)
sb_gu_mean = sb_gu_mean.rename(columns={'gu' : 'SIG_KOR_NM'} )
id_gu_mean = id_gu_mean.rename(columns={'gu' : 'SIG_KOR_NM'} )
sb_gu_mean = sb_gu_mean.rename(columns={'dist2sub' : '평균거리_sb'} )
id_gu_mean = id_gu_mean.rename(columns={'dist2sub' : '평균거리_ed'} )
sigu = sigu.merge(sb_gu_mean, on='SIG_KOR_NM')
sigu = sigu.merge(id_gu_mean, on='SIG_KOR_NM')
# 이디야 최단거리(평균) - 스타벅스 최단거리(평균)
sigu['평균거리_차이'] = sigu['평균거리_ed']-sigu['평균거리_sb']
sigu.head()
| SIG_CD | SIG_ENG_NM | SIG_KOR_NM | geometry | CTPRVN_CD | starbucks_count | ediya_count | sb_id | sb_id_1 | 공시지가 평균 | 역개수 | 평균거리_sb | 평균거리_ed | 평균거리_차이 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 11110 | Jongno-gu | 종로구 | POLYGON ((956615.453 1953567.199, 956621.579 1... | 11 | 39 | 35 | 4 | SB: +4 | 5938143 | 15 | 404 | 429 | 25 |
| 1 | 11140 | Jung-gu | 중구 | POLYGON ((957890.386 1952616.746, 957909.908 1... | 11 | 52 | 34 | 18 | SB: +18 | 9949269 | 23 | 377 | 415 | 38 |
| 2 | 11170 | Yongsan-gu | 용산구 | POLYGON ((953115.761 1950834.084, 953114.206 1... | 11 | 24 | 13 | 11 | SB: +11 | 6812485 | 10 | 496 | 530 | 34 |
| 3 | 11200 | Seongdong-gu | 성동구 | POLYGON ((959681.109 1952649.605, 959842.412 1... | 11 | 14 | 20 | -6 | ED: +6 | 4884766 | 14 | 396 | 469 | 73 |
| 4 | 11215 | Gwangjin-gu | 광진구 | POLYGON ((964825.058 1952633.25, 964875.565 19... | 11 | 19 | 20 | -1 | ED: +1 | 4371127 | 11 | 368 | 580 | 212 |
add_text_sb = '최단거리(평균)가 짧을수록 파랑색, 길수록 붉은색'
title_text = '스타벅스 매장에서 지하철역까지 최단거리 구별 평균 COLORMAP'
map_color_text(sigu,'평균거리_sb','coolwarm','최단거리 평균 최소값~최대값','SIG_KOR_NM',add_text_sb,title_text)
add_text_sb = '최단거리(평균)가 짧을수록 파랑색, 길수록 붉은색'
title_text = '이디야 매장에서 지하철역까지 최단거리 구별 평균 COLORMAP'
map_color_text(sigu,'평균거리_ed','coolwarm','최단거리 평균 최소값~최대값','SIG_KOR_NM',add_text_sb,title_text)
sigu['평균거리_ed'].mean(),sigu['평균거리_sb'].mean(),sigu['평균거리_차이'].mean()
(583.5464143802974, 464.65921912733825, 118.8871952529592)
이디야의 평균 최단거리가 스타벅스보다 119m 더 길다.
add_text_sb = '이디야 최단거리(평균)가 스타벅스보다 길수록 붉은색, 짧을수록 파랑색'
title_text = '이디야 최단거리(평균) & 스타벅스 최단거리(평균) 차이 COLORMAP'
map_color_text1(sigu,'평균거리_차이','coolwarm','최단거리 평균 차이 최소값~최대값','SIG_KOR_NM',add_text_sb,title_text)
Image('seoul_sb_ed02.png')
지하철역 여러 호선이 있는 역 리네임
num = subway[subway['SUBWAY_STA'].isnull()].index.tolist()
subway['SUBWAY_STA'][num] = "noname역"
subway = duplicate_rename(subway)
지하철역이 속한 구 할당
SIG_KOR_NM = []
for i in range(subway.shape[0]):
subim = subway.loc[subway['SUBWAY_STA'] == subway['SUBWAY_STA'][i], 'geometry'].values[0]# squeeze()를 하면 오류난다.
for j in range(sigu.shape[0]):
guim = sigu.loc[sigu['SIG_KOR_NM'] == sigu['SIG_KOR_NM'][j], 'geometry'].values[0]
subim.within(guim)
if subim.within(guim)==True:
SIG_KOR_NM.append(sigu['SIG_KOR_NM'][j])
if len(SIG_KOR_NM)<(i+1):
SIG_KOR_NM.append('없음')
subway['SIG_KOR_NM'] = SIG_KOR_NM
두 브랜드의 매장 수가 가장 많은 '강남구'와 이디야 매장 수가 훨씬 더 많은 '강서구'
sigu.loc[[15,22],['SIG_KOR_NM','starbucks_count','ediya_count','sb_id_1','평균거리_sb','평균거리_ed','평균거리_차이']]
| SIG_KOR_NM | starbucks_count | ediya_count | sb_id_1 | 평균거리_sb | 평균거리_ed | 평균거리_차이 | |
|---|---|---|---|---|---|---|---|
| 15 | 강서구 | 28 | 43 | ED: +15 | 378 | 512 | 134 |
| 22 | 강남구 | 91 | 42 | SB: +49 | 489 | 553 | 63 |
gu_near_vi('G_gang.pkl','강남구')
강남구의 경우 이디야의 최단거리(평균)가 스타벅스보다 64m 더 길다.
강남구-스타벅스의 경우 파랑색 경로가 붉은색(또는 흰색)보다 조금 더 많다. 이디야의 경우는 파랑색 경로가 훨신 더 많다.
gu_near_vi('G_gangsu.pkl','강서구')
강서구의 경우 이디야의 최단거리(평균)가 스타벅스보다 134m 더 길다.
강서구-스타벅스의 경우 파랑색 경로보다 붉은색(또는 흰색) 경로가 훨씬 더 많다. 이디야의 경우는 파랑색 경로가 더 많다.